﻿namespace LogManager.Utils.Unity
{
    using LogManager.Utils.ChangeTracking;
    using Microsoft.Practices.Unity.InterceptionExtension;
    using NSubstitute;
    using NUnit.Framework;
    using System.ComponentModel;

    public class TestPropertyChangedBehavior
    {

        [Test]
        public void PropertyChangedBehavior_Invoke_AnyClass_EventNotRaised()
        {
            var propBehavior = new PropertyChangedBehavior();
            var sample = new SampleClass();
            var propertySetter = typeof(SampleClass).GetProperty("Title").GetSetMethod();

            bool raiseCalled = false;
            sample.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
                                        {
                                            raiseCalled = true;
                                        };

            var methodInvocation = Substitute.For<IMethodInvocation>();
            methodInvocation.MethodBase.Returns(propertySetter);
            methodInvocation.Target.Returns(sample);

            var getNextDel = Substitute.For<GetNextInterceptionBehaviorDelegate>();

            var result = propBehavior.Invoke(methodInvocation, getNextDel);

            Assert.AreEqual(raiseCalled, false, "Raise PropertyChanged should not be called because class is not PropertyChangeBase");
        }

        [Test]
        public void PropertyChangedBehavior_Invoke_ClassIsPropertyChangeBase_EventRaised()
        {
            var propBehavior = new PropertyChangedBehavior();
            var sample = new SampleClassChangeBase();
            var propertySetter = typeof(SampleClassChangeBase).GetProperty("Title").GetSetMethod();

            bool raiseCalled = false;
            sample.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
            {
                raiseCalled = true;
                Assert.AreEqual(e.PropertyName, "Title");
                Assert.AreEqual(sample, sender);
            };

            var methodInvocation = Substitute.For<IMethodInvocation>();
            methodInvocation.MethodBase.Returns(propertySetter);
            methodInvocation.Target.Returns(sample);

            var getNextDel = Substitute.For<GetNextInterceptionBehaviorDelegate>();
            var result = propBehavior.Invoke(methodInvocation, getNextDel);

            Assert.AreEqual(raiseCalled, true, "Raise PropertyChanged should be called because class is PropertyChangeBase");
        }

        [Test]
        public void PropertyChangedBehavior_Invoke_Method_EventNotRaised()
        {
            var propBehavior = new PropertyChangedBehavior();
            var sample = new SampleClassChangeBase();
            var method = typeof(SampleClassChangeBase).GetMethod("AnyMethod");

            bool raiseCalled = false;
            sample.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
            {
                raiseCalled = true;
            };

            var methodInvocation = Substitute.For<IMethodInvocation>();
            methodInvocation.MethodBase.Returns(method);
            methodInvocation.Target.Returns(sample);

            var getNextDel = Substitute.For<GetNextInterceptionBehaviorDelegate>();
            var result = propBehavior.Invoke(methodInvocation, getNextDel);

            Assert.AreEqual(raiseCalled, false, "Raise PropertyChanged should not be called because method is not named 'set_...'");
        }

    }

    public class SampleClass : INotifyPropertyChanged
    {
        public string Title { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        private void DisableWarning() { PropertyChanged(null, null); }
    }

    public class SampleClassChangeBase : PropertyChangeBase
    {
        public string Title { get; set; }

        public void AnyMethod() { }
    }
}
